#include "napi/native_api.h"

// js函数回调
static napi_ref callback = nullptr;

/**
 * 求两数之和
 * @param env
 * @param info
 * @return 
 */
static napi_value Add(napi_env env, napi_callback_info info)
{
    // 获取 2 个参数，napi_value是对 JS 类型的封装
    size_t argc = 2;
    napi_value argv[2] = {nullptr};
    
    // 调用napi_get_cb_info方法，从 info 中读取传递进来的参数放入argv里
    napi_get_cb_info(env, info, &argc, argv , nullptr, nullptr);

    // 获取参数并校验类型
    napi_valuetype valuetype0;
    napi_typeof(env, argv[0], &valuetype0);
    napi_valuetype valuetype1;
    napi_typeof(env, argv[1], &valuetype1);
    
    // 调用napi_get_value_double把 napi_value 类型转换成 C++ 的 double 类型
    double value0;
    napi_get_value_double(env, argv[0], &value0);
    double value1;
    napi_get_value_double(env, argv[1], &value1);
    
    
    // 调用napi_create_double方法把 C++类型转换成 napi_value 类型
    napi_value sum;
    napi_create_double(env, value0 + value1, &sum);
    
    // 返回 napi_value 类型
    return sum;
}

/**
 * 注册回调函数
 * @param env
 * @param info
 * @return 
 */
static napi_value RegisterCallback(napi_env env, napi_callback_info info) 
{
    size_t argc = 1;
    napi_value argv[1] = {nullptr};
    
    napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
    
    napi_create_reference(env, argv[0], 1, &callback);
    
    return nullptr;
}

/**
 * 执行回调函数，不带参数
 * @param env
 * @param info
 * @return 
 */
static napi_value HandleCallbackWithoutParams(napi_env env, napi_callback_info info)
{
    
    napi_value global;

    napi_get_global(env, &global);
    
    napi_value cb = nullptr;
    napi_get_reference_value(env, callback, &cb);

    napi_value result;
    
    napi_status status = napi_call_function(env, global, cb, 0 , nullptr, &result);
    
    if (status != napi_ok) return nullptr;
    
    return result;
}

/**
 * 执行回调函数，带参数
 * @param env
 * @param info
 * @return 
 */
static napi_value HandleCallbackWithParams(napi_env env, napi_callback_info info)
{
    napi_value argv[2] = {nullptr};
    
    napi_valuetype valuetype0;
    napi_typeof(env, argv[0], &valuetype0);

    napi_valuetype valuetype1;
    napi_typeof(env, argv[1], &valuetype1);
    
    double value1 = 2;
    double value2 = 3;

    // 创建两个double，给callback调用
    napi_create_double(env, value1, &argv[0]);
    napi_create_double(env, value2, &argv[1]);
    
    napi_value global;
    napi_get_global(env, &global);
    
    napi_value cb = nullptr;
    napi_get_reference_value(env, callback, &cb);
    
    napi_valuetype type;
    napi_typeof(env, cb, &type);

    napi_value result;
    // 调用回调函数
    napi_status status = napi_call_function(env, global, cb, 2, argv, &result);
    
    if (status != napi_ok) return nullptr;
    
    return result;
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_value fn;
    // 根据C++侧函数Add创建函数fn
    napi_create_function(env, nullptr, 0, Add, nullptr, &fn);
    // 将创建的函数fn导出，函数名为newAdd
    napi_set_named_property(env, exports, "newAdd", fn);
    
    napi_property_descriptor desc[] = {
        { "add", nullptr, Add, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "registerCallback", nullptr, RegisterCallback, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "handleCallbackWithoutParams", nullptr, HandleCallbackWithoutParams, nullptr, nullptr, nullptr, napi_default, nullptr },
        { "handleCallbackWithParams", nullptr, HandleCallbackWithParams, nullptr, nullptr, nullptr, napi_default, nullptr },
    };
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version =1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
